﻿using System;
using SoftwareConsulting.BI11.NumericalMethods.Curves;
using SoftwareConsulting.BI11.NumericalMethods.Statistics;
using SoftwareConsulting.BI11.Studio.InternalServices;

namespace SoftwareConsulting.BI11.NumericalMethods.Statistics
{
    /// <summary>
    /// Класс равномерного распределения
    /// </summary>
    public sealed class UniformDistribution : ProbabilityDensityFunction
    {	    
        private double _lowLimit;//нижняя граница	    
        private double _highLimit;//верхняя граница

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="lowLimit"></param>
        /// <param name="highLimit"></param>
        public UniformDistribution(double lowLimit, double highLimit)
        {
            if (lowLimit >= highLimit)
                throw new ArgumentOutOfRangeException("lowLimit");
            _lowLimit = lowLimit;
            _highLimit = highLimit;
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="histogram">Гистограмма, из которой вытягиваются параметры по наилучшим предположениям</param>
        public UniformDistribution(Histogram histogram)
        {
            _highLimit = histogram.StandardDeviation * 1.73205080756888;
            double c = histogram.Average;
            _lowLimit = c - _highLimit;
            _highLimit += c;
        }

        /// <summary>
        /// Возвращает среднее распределения
        /// </summary>
        public override double Average
        {
            get 
            { 
                return (_lowLimit + _highLimit) * 0.5; 
            }
            set
            {
                Assert.Fail(Assert.Id.Assert00293);//для данного распределения не поддерживается
            }
        }

        /// <summary>
        /// Возвращает значение функции плотности распределения
        /// </summary>
        /// <param name="x"></param>
        /// <returns>вероятность, нахождения случайной переменной меньше или равной, чем X</returns>
        public override double GetDistributionValue(double x)
        {
            if (x < _lowLimit)
                return 0;
            if (x < _highLimit)
                return (x - _lowLimit) / (_highLimit - _lowLimit);
            return 1;
        }

        /// <summary>
        /// Возвращает эксцесс распределения
        /// </summary>
        public override double Kurtosis
        {
            get 
            { 
                return -1.2; 
            }
        }

        /// <summary>
        /// Возвращает название распределения
        /// </summary>
        public override string Name
        {
            get { return "Uniform distribution"; }
        }

        /// <summary>
        /// Возвращает/устанавливает параметры распределения
        /// </summary>
        public override double[] Parameters
        {
            get 
            {
                return new double[] { _lowLimit, _highLimit }; 
            }
            set
            {
                _lowLimit = value[0];
                _highLimit = value[1];
            }
        }

        /// <summary>
        /// Возвращает значение, для которого функция распределения равна указанному значению X
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        protected override double GetInversedValue(double x)
        {
            return (_highLimit - _lowLimit) * x + _lowLimit;
        }

        /// <summary>
        /// Возвращает коэффициент уклона распределения
        /// </summary>
        public override double Skewness
        {
            get 
            { 
                return 0; 
            }
        }

        /// <summary>
        /// Вычисляет значение, основываясь на функции плотности
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public override double GetValue(double x)
        {
            if (x < _lowLimit)
                return 0;
            if (x < _highLimit)
                return 1 / (_highLimit - _lowLimit);
            return 0;
        }

        /// <summary>
        /// Возвращает дисперсию распределения
        /// </summary>
        public override double Variance
        {
            get
            {
                double range = _highLimit - _lowLimit;
                return range * range / 12;
            }
        }
    }
}
